package com.xhj.mybatis.reflection;

import com.xhj.mybatis.reflection.factory.ObjectFactory;
import com.xhj.mybatis.reflection.property.PropertyTokenizer;
import com.xhj.mybatis.reflection.wrapper.*;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * MetaObject
 *
 * @author XJks
 * @description MetaObject 类的主要作用是为任意对象提供统一的属性访问和操作接口。它通过包装对象，屏蔽了对象类型（如 JavaBean、Map、Collection 等）的差异，支持多级属性（如 user.address.street）的读取和设置。这样，MyBatis 框架在处理对象属性时，无需关心对象的具体类型和访问方式，提高了代码的通用性和灵活性。TODO:元对象门面：统一入口。对外只暴露 MetaObject，内部把“路径解析、包装分派、反射调用”全接好。
 */
public class MetaObject {

    /**
     * 原始对象，被包装的目标对象
     */
    private final Object originalObject;

    /**
     * 对原始对象的包装器，负责属性的读写等操作
     */
    private final ObjectWrapper objectWrapper;

    /**
     * 用于创建对象的工厂
     */
    private final ObjectFactory objectFactory;

    /**
     * 用于创建对象包装器的工厂
     */
    private final ObjectWrapperFactory objectWrapperFactory;

    /**
     * 用于反射相关操作的工厂
     */
    private final ReflectorFactory reflectorFactory;

    /**
     * 构造方法，初始化MetaObject及其包装器
     *
     * @param object               需要包装的原始对象
     * @param objectFactory        对象工厂
     * @param objectWrapperFactory 包装器工厂
     * @param reflectorFactory     反射工厂
     */
    private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
        this.originalObject = object;
        this.objectFactory = objectFactory;
        this.objectWrapperFactory = objectWrapperFactory;
        this.reflectorFactory = reflectorFactory;

        // 根据对象类型选择合适的包装器
        if (object instanceof ObjectWrapper) {
            // 如果本身就是ObjectWrapper，直接赋值
            this.objectWrapper = (ObjectWrapper) object;
        } else if (objectWrapperFactory.hasWrapperFor(object)) {
            // 如果工厂能为该对象提供包装器，则使用工厂创建
            this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
        } else if (object instanceof Map) {
            // 如果是Map类型，使用MapWrapper
            this.objectWrapper = new MapWrapper(this, (Map) object);
        } else if (object instanceof Collection) {
            // 如果是集合类型，使用CollectionWrapper
            this.objectWrapper = new CollectionWrapper(this, (Collection) object);
        } else {
            // 否则，使用BeanWrapper（普通JavaBean）
            this.objectWrapper = new BeanWrapper(this, object);
        }
    }

    /**
     * 静态工厂方法，创建MetaObject实例
     *
     * @param object               需要包装的对象
     * @param objectFactory        对象工厂
     * @param objectWrapperFactory 包装器工厂
     * @param reflectorFactory     反射工厂
     * @return MetaObject实例或空对象
     */
    public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
        if (object == null) {
            // 如果对象为null，返回空MetaObject
            return SystemMetaObject.NULL_META_OBJECT;
        } else {
            // 否则创建新的MetaObject
            return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
        }
    }

    /**
     * 获取对象工厂
     *
     * @return 对象工厂
     */
    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }

    /**
     * 获取包装器工厂
     *
     * @return 包装器工厂
     */
    public ObjectWrapperFactory getObjectWrapperFactory() {
        return objectWrapperFactory;
    }

    /**
     * 获取反射工厂
     *
     * @return 反射工厂
     */
    public ReflectorFactory getReflectorFactory() {
        return reflectorFactory;
    }

    /**
     * 获取原始对象
     *
     * @return 原始对象
     */
    public Object getOriginalObject() {
        return originalObject;
    }

    /**
     * 查找属性名，支持驼峰转下划线等映射
     *
     * @param propName            属性名
     * @param useCamelCaseMapping 是否使用驼峰映射
     * @return 实际属性名
     */
    public String findProperty(String propName, boolean useCamelCaseMapping) {
        return objectWrapper.findProperty(propName, useCamelCaseMapping);
    }

    /**
     * 获取所有getter方法对应的属性名
     *
     * @return 属性名数组
     */
    public String[] getGetterNames() {
        return objectWrapper.getGetterNames();
    }

    /**
     * 获取所有setter方法对应的属性名
     *
     * @return 属性名数组
     */
    public String[] getSetterNames() {
        return objectWrapper.getSetterNames();
    }

    /**
     * 获取指定属性的setter方法参数类型
     *
     * @param name 属性名
     * @return 参数类型
     */
    public Class<?> getSetterType(String name) {
        return objectWrapper.getSetterType(name);
    }

    /**
     * 获取指定属性的getter方法返回类型
     *
     * @param name 属性名
     * @return 返回类型
     */
    public Class<?> getGetterType(String name) {
        return objectWrapper.getGetterType(name);
    }

    /**
     * 判断是否有指定属性的setter方法
     *
     * @param name 属性名
     * @return 是否有setter
     */
    public boolean hasSetter(String name) {
        return objectWrapper.hasSetter(name);
    }

    /**
     * 判断是否有指定属性的getter方法
     *
     * @param name 属性名
     * @return 是否有getter
     */
    public boolean hasGetter(String name) {
        return objectWrapper.hasGetter(name);
    }

    /**
     * 获取指定属性的值，支持多级属性（如user.address.street）
     *
     * @param name 属性名
     * @return 属性值
     */
    public Object getValue(String name) {
        // 用于解析属性名，支持多级属性（如 user.address.street）
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 判断当前属性名是否还有子属性（即是否为多级属性）
        if (prop.hasNext()) {
            // 如果有子属性，递归获取子属性对应的 MetaObject
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            // 如果子属性不存在，返回 null
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return null;
            } else {
                // 递归调用 getValue 获取下一级子属性的值
                return metaValue.getValue(prop.getChildren());
            }
        } else {
            // 如果没有子属性，直接通过包装器获取属性值
            return objectWrapper.get(prop);
        }
    }

    /**
     * 设置指定属性的值，支持多级属性
     *
     * @param name  属性名
     * @param value 属性值
     */
    public void setValue(String name, Object value) {
        // 解析属性名
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            // 有子属性，递归设置
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            // TODO:如果对应属性的 MetaObject 不存在，则需要进入 if 分支中进行可能的实例化操作，如果设置的值为 null，则直接返回不进行任何操作
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                if (value == null) {
                    // 如果值为null，不实例化子路径
                    return;
                } else {
                    // 实例化子属性对象
                    metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
                }
            }
            metaValue.setValue(prop.getChildren(), value);
        } else {
            // 没有子属性，直接设置
            objectWrapper.set(prop, value);
        }
    }

    /**
     * 获取指定属性的MetaObject包装
     *
     * @param name 属性名
     * @return 属性对应的MetaObject
     */
    public MetaObject metaObjectForProperty(String name) {
        // TODO:获取指定属性名对应的原生属性值（支持多级属性，如 user.address.street），该属性值是未被包装的原始对象，即不是 MetaObject 类型
        Object value = getValue(name);
        // TODO:使用获取到的属性值，结合工厂类，创建并返回一个新的 MetaObject 实例，将属性值进行包装
        // 如果 value 为 null，则返回一个特殊的空 MetaObject（由 forObject 方法内部处理）
        return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
    }

    /**
     * 获取对象包装器
     *
     * @return 对象包装器
     */
    public ObjectWrapper getObjectWrapper() {
        return objectWrapper;
    }

    /**
     * 判断当前对象是否为集合类型
     *
     * @return 是否为集合
     */
    public boolean isCollection() {
        return objectWrapper.isCollection();
    }

    /**
     * 向集合添加元素
     *
     * @param element 要添加的元素
     */
    public void add(Object element) {
        objectWrapper.add(element);
    }

    /**
     * 向集合添加多个元素
     *
     * @param list 要添加的元素列表
     * @param <E>  元素类型
     */
    public <E> void addAll(List<E> list) {
        objectWrapper.addAll(list);
    }

}
